---
title: 理论篇
---
并发编程并不是 Java 特有的语言特性，它是一个通用且早已成熟的领域，Java 只是根据自身情况做了实现。

**并发编程可以总结为三个核心问题：分工、同步、互斥**

分工指的是如何高效地拆解任务并分配给线程，同步指的是线程之间如何协作，互斥则是保证同一时刻只允许一个线程访问共享资源。

这三个核心问题是跨语言的。Java SDK 并发包很大部分内容都是按照这三个维度组织的。其余的一部分内容则是并发容器和原子类，这些容易理解，属于辅助工具。



### 分工
分工，类似于现实中一个组织完成一个项目，项目经理要拆分任务，安排给合适的成员去完成。

Java SDK 并发包里的 Executor 、Fork/Join、Future 本质上都是一种分工方法。除此之外，并发编程领域的一些设计模式，基本上都是和分工方法相关，例如生产者-消费者、Thread-Per-Message，Worker Thread模式等都是用来指导你如何分工的。


### 同步
分好工之后，就是具体执行了。在项目执行过程中，任务之间是有依赖的，一个任务结束后，依赖它的后续任务就可以开始了，后续任务怎么知道可以开始了？这个就是要靠沟通协作了。

在并发编程领域的同步，指的就是线程间的协作，本质和现实世界中的协作没什么区别，不过是一个线程完成了一个任务，如何通知后续执行任务的线程开工而已。


协作一般是和分工相关的。Java SDK 并发包里的 Executor、Fork/Join、Future（解决了主线程和异步线程之间的协作问题） 本质上都是分工方法，但同时也能解决线程协作的问题。
除此之外，Java SDK 提供的 CountDownLatch、CyclicBarrier、Phaser、Exchanger 也都是用来解决线程协作问题的。

工作中遇到的线程协作问题，基本上都可以描述为这样的一个问题：**当某个条件不满足时，线程需要等待，当某个条件满足时，线程需要被唤醒**。
:::tip
在生产者-消费者模型中也有类似的描述，”当队列满时，生产者线程等待，当队列不满时，生产者线程需要被唤醒执行；当队列空时，消费者线程阻塞，当队列不空时，消费者线程需要被唤醒执行。“
:::
### 互斥
分工、同步主要强调的是性能，并发程序里还有一部分是关于正确性的，专业术语叫 ”线程安全“。

在并发程序里，当多个线程访问同一个变量时，结果是不确定的。而导致不确定的主要源头是可见性问题、有序性问题和原子性问题。

为了解决这三个问题，Java 语言引入了内存模型，内存模型提供了一系列规则，利用这些规则，我们可以避免可见性问题，有序性问题，但是还不足以解决线程安全问题。

解决线程安全问题的核心方法还是互斥。

实现互斥的核心技术就是锁，Java 语言里的 synchronized、SDK 里的各种 Lock 都能解决互斥问题。

虽说锁解决了安全性问题，但同时也带来了性能问题，那如何保证安全性的同时又尽量提高性能呢？可以分场景优化，Java SDK 提供的 ReadWriteLock 、StampedLock 就可以优化读多写少场景下的锁的性能。
还可以使用无锁的数据结构，原子类、不共享变量或变量只允许读。这方面，Java 提供了 ThreadLocal 和 final 关键字，还有一种 Copy-on-write 的模式。


import DocCardList from '@theme/DocCardList';


<DocCardList/>
